跳到主要内容

Label/Selector 对照

Selector(标签选择器)就两种语法:等值匹配对应 matchLabels,集合匹配对应 matchExpressions。难记的是各资源的字段位置和支持范围,本篇一张表对照清楚。

等值匹配​

判断 key 等不等于某个值,三种操作符:

操作符含义kubectl 写法YAML 写法
=等于-l app=webmatchLabels 键值对
==等于(与 = 完全等价)-l app==web同上
!=不等于-l 'app!=web'matchLabels 不支持,改用 NotIn

YAML 里对应字段是 matchLabels,多个键值对之间是与关系:

selector:
matchLabels:
app: web
tier: frontend

集合匹配​

判断 key 的值是否落在某个集合里,四种运算符:

operator含义values 是否必填kubectl 写法
In值在集合中必填(至少一个)-l 'env in (prod,staging)'
NotIn值不在集合中必填(至少一个)-l 'env notin (dev)'
Exists存在这个 key(不看值)不填-l debug
DoesNotExist不存在这个 key不填-l '!debug'

YAML 里对应字段是 matchExpressions,每条表达式由 key、operator、values 三部分组成:

selector:
matchExpressions:
- key: tier
operator: In
values: ["frontend", "backend"]
- key: track
operator: NotIn
values: ["canary"]
- key: debug
operator: DoesNotExist

matchLabels 和 matchExpressions 可以混用,所有条件之间都是与关系:

selector:
matchLabels:
app: web
matchExpressions:
- key: env
operator: In
values: ["prod"]

各资源 Selector 写法​

资源 / 场景字段位置支持的语法创建后能否修改
Servicespec.selector仅等值键值对可改
Deploymentspec.selector(matchLabels / matchExpressions)两种都支持不可变
ReplicaSet / DaemonSet / StatefulSetspec.selector两种都支持不可变
Jobspec.selector(一般不手写,由控制器自动注入)两种都支持不可变
PVCspec.selector两种都支持不可变
NetworkPolicy 选 Podspec.podSelector两种都支持可改
NetworkPolicy 选命名空间ingress/egress 规则里的 namespaceSelector两种都支持可改
NodeAffinitynodeSelectorTerms[].matchExpressions仅表达式(另支持 Gt、Lt)随 Pod 模板滚动生效
PodAffinity / PodAntiAffinitylabelSelector(matchLabels / matchExpressions)两种都支持随 Pod 模板滚动生效
kubectl 查询过滤-l / --selector 参数两种都支持不涉及

Service​

只支持等值键值对,选中 labels 完全包含这些键值对的 Pod:

apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web # 选中带 app=web 的 Pod
ports:
- port: 80
targetPort: 8080

Deployment​

spec.selector 必须能被 Pod 模板 template.metadata.labels 命中,且创建后不可变:

apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
selector:
matchLabels:
app: web # 必须被下面模板的 labels 包含
template:
metadata:
labels:
app: web
env: prod # 模板多出的 label 无妨,反过来则创建报错
spec:
containers:
- name: web
image: nginx:1.27

NetworkPolicy​

podSelector 选本命名空间内的 Pod,namespaceSelector 选整个命名空间;同一条 from 里两者同时写是与关系,写空 {} 表示全选:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
spec:
podSelector:
matchLabels:
app: web # 策略作用于哪些 Pod,空 {} 表示全部
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: frontend
podSelector:
matchLabels:
app: gateway

NodeAffinity / PodAffinity​

NodeAffinity 的 selector 只有 matchExpressions 一种写法,且运算符在四种之外还支持 Gt、Lt(比较整数值);PodAffinity 的 labelSelector 则是完整的 LabelSelector,两种语法都能用:

# 节点亲和:只调度到 SSD 节点
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values: ["ssd"]
# Pod 亲和:尽量和 cache 的 Pod 落在同一节点
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: cache
topologyKey: kubernetes.io/hostname

两组关系要分清:nodeSelectorTerms 多条之间是或,每条 term 内的 matchExpressions 之间是与。NodeAffinity 的 term 里还有 matchFields,可以按字段(如 metadata.name)选节点。

kubectl -l 查询速查​

-l(--selector)用逗号分隔多个条件,逗号 = 与:

需求写法
等于-l app=web
不等于-l 'app!=web'
多条件(与)-l 'app=web,env=prod'
值在集合中-l 'env in (prod,staging)'
值不在集合中-l 'env notin (dev)'
有这个 key-l debug
没有这个 key-l '!debug'
混合写法-l 'app=web,env in (prod,staging),!debug'
参数一律加单引号

!=、!、()、, 在 shell 里有特殊含义(交互式 bash 里 ! 还会触发历史展开),不加引号很容易报错。-l 后面不管写什么,都先用单引号包起来。

-l 不只 get 能用:delete、logs、label、describe 等批量操作命令都接受。

常用系统标签​

节点与拓扑标签​

kubelet 上报节点信息时自动打上的标签,调度与亲和规则里直接引用:

标签含义
kubernetes.io/hostname节点主机名
kubernetes.io/os操作系统(linux、windows)
kubernetes.io/archCPU 架构(amd64、arm64)
topology.kubernetes.io/zone可用区(云厂商注入)
topology.kubernetes.io/region地域(云厂商注入)
node-role.kubernetes.io/control-plane控制平面节点标记(值为空)
node-role.kubernetes.io/master旧版控制平面标记(kubeadm 1.24 起新节点不再打)

node-role 类标签只看 key 不看值,配合 Exists / DoesNotExist 用,例如「不要调度到控制平面」就是 node-role.kubernetes.io/control-plane + DoesNotExist。

app.kubernetes.io 推荐标签​

社区约定的一组应用管理标签(recommended labels),Helm chart 和周边工具默认认这套:

标签含义示例
app.kubernetes.io/name应用名mysql
app.kubernetes.io/instance实例名(区分同一应用的多个部署)mysql-prod
app.kubernetes.io/version应用版本"5.7.21"
app.kubernetes.io/component在架构中的角色database
app.kubernetes.io/part-of所属的上层应用wordpress
app.kubernetes.io/managed-by管理工具helm

Label 命名规则​

key 的结构是 [prefix/]name,prefix 可选:

部分限制
name(必填)最长 63 字符,首末必须是字母数字,中间可用 -、_、.
prefix(可选)DNS 子域名格式,最长 253 字符,以 / 与 name 分隔
value最长 63 字符,规则同 name,可以为空

kubernetes.io/ 和 k8s.io/ 前缀保留给 Kubernetes 核心组件,自定义标签不要占用。

常见坑​

Deployment 的 selector 创建后不可修改

spec.selector 是不可变字段,创建后再改 apply 直接报错(field is immutable)。规划标签时别把每次发版都变的值(如版本号)放进 selector 命中的 label 里;真要改只能删掉 Deployment 重建,Pod 会全部重建。

Service selector 必须和 Pod 的 labels 对得上

Service 纯靠 label 找 Pod:selector 里的键值对必须被 Pod 的 labels 包含。Deployment 场景下要三方对齐:spec.selector ↔ template.metadata.labels ↔ Service 的 spec.selector。对不上时 Endpoints 为空,Service 有 ClusterIP 却没后端,排障先跑 kubectl get endpoints。

标签交给清单文件管理

kubectl label 手打的标签容易和 YAML 清单漂移,下次 apply 可能被覆盖回去。长期有效的标签写进清单,纳入版本管理;临时标记(排障、灰度)再用命令行。